package com.yycx.module.bus.provider.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.afterturn.easypoi.excel.export.styler.ExcelExportStylerDefaultImpl;
import com.alibaba.fastjson.util.TypeUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.yycx.common.base.entity.EntityMap;
import com.yycx.common.base.utils.FlymeUtils;
import com.yycx.common.constants.CommonConstants;
import com.yycx.common.mybatis.base.service.impl.BaseServiceImpl;
import com.yycx.common.mybatis.model.ResultBody;
import com.yycx.common.mybatis.query.CriteriaDelete;
import com.yycx.common.mybatis.query.CriteriaQuery;
import com.yycx.common.mybatis.query.CriteriaSave;
import com.yycx.common.security.OpenHelper;
import com.yycx.common.utils.ApiAssert;
import com.yycx.common.utils.DateUtils;
import com.yycx.module.bus.client.entity.*;
import com.yycx.module.bus.provider.mapper.BusFinanceMapper;
import com.yycx.module.bus.provider.service.*;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.*;

/**
 * 账务表接口实现类
 *
 * @author flyme
 * @date 2021-01-05
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class BusFinanceServiceImpl extends BaseServiceImpl<BusFinanceMapper, BusFinance> implements BusFinanceService {

    @Autowired
    private BusFinanceDetailsService detailsService;

    @Resource
    private BusDeptService deptService;

    @Resource
    private BusSalemanService salemanService;

    @Autowired
    private BusOrderDetailsService orderDetailsService;


    @Override
    public ResultBody beforeAdd(CriteriaSave cs, BusFinance finance, EntityMap extra) {
        BusFinance check = getDateByMonth(finance, finance.getFinanceMonth(), 2);
        ApiAssert.isEmpty("所选月份对账表已创建", check);
        finance.setFinanceType(2);
        finance.setFinanceState(0);
        finance.setCompanyId(OpenHelper.getCompanyId());
        finance.setSaleAmount(new BigDecimal("0"));
        return ResultBody.ok();
    }


    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public ResultBody beforePageList(CriteriaQuery<BusFinance> cq, BusFinance finance, EntityMap requestMap) {
        Integer financeType = requestMap.getInt("financeType", 2);
        cq.select(BusFinance.class, "*");
        cq.select(BusDept.class, "deptName");
        cq.select(BusSaleman.class, "saleManName");
        cq.eq("finance.financeMonth", requestMap.get("financeMonth"));
        cq.eq(true, "finance.financeType", financeType);
        cq.eq("finance.deptId", requestMap.get("deptId"));
        cq.like("saleman.saleManName", requestMap.get("saleManName"));
        cq.eq("finance.companyId", OpenHelper.getCompanyId());
        cq.orderByDesc("financeMonth");
        cq.createJoin(BusDept.class).setMainField("deptId").setJoinField("deptId");
        cq.createJoin(BusSaleman.class).setMainField("saleManId").setJoinField("saleManId");
        cq.orderByDesc("finance.createTime");
        return ResultBody.ok();
    }

    @Override
    public List<EntityMap> afterPageList(CriteriaQuery<BusFinance> cq, List<EntityMap> data, ResultBody resultBody) {
        for (EntityMap datum : data) {
            String financeMonth = datum.get("financeMonth") + "-01";
            Date fisrtDay = DateUtils.parseDate(financeMonth);
            Date date0 = DateUtils.addMonths(fisrtDay, 1);
            String data1 = DateUtils.getYear() + "-" + DateUtils.getMonth() + "-01";
            datum.put("allowInit", 0);
            if (DateUtils.formatDate(date0).equals(data1)) {
                datum.put("allowInit", 1);
            }
        }
        return super.afterPageList(cq, data, resultBody);
    }

    @Override
    public ResultBody afterDelete(CriteriaDelete cd, Serializable[] ids) {
        Serializable financeId = cd.getIdValue();
        detailsService.removeByFinanceId(financeId);
        return super.afterDelete(cd, ids);
    }

    @Override
    public ResultBody importData(MultipartFile file, Map params) {
        try {
            String financeMonth = (String) params.get("financeMonth");
            Long deptId = TypeUtils.castToLong(params.get("deptId"));
            Long saleManId = TypeUtils.castToLong(params.get("saleManId"));
            Long userId = OpenHelper.getUserId();
            ImportParams importParams = new ImportParams();
            importParams.setTitleRows(2);
            importParams.setReadRows(1);
            List<Map<Object, Object>> ExcelList = ExcelImportUtil.importExcel(file.getInputStream(), Map.class, importParams);
            List<BusFinance> busFinanceList = new ArrayList<>();
            for (Map<Object, Object> objectMap : ExcelList) {
                BigDecimal saleAmount = TypeUtils.castToBigDecimal(objectMap.get("累计发货金额"));
                BigDecimal returnAmount = TypeUtils.castToBigDecimal(objectMap.get("累计客户回款"));
                BigDecimal debtAmount = TypeUtils.castToBigDecimal(objectMap.get("累计客户欠款"));
                BigDecimal cBondAmount = TypeUtils.castToBigDecimal(objectMap.get("累计保证金收款"));
                BigDecimal cBondReturnAmount = TypeUtils.castToBigDecimal(objectMap.get("累计保证金退款"));
                BigDecimal settleAbleAmount = TypeUtils.castToBigDecimal(objectMap.get("累计应付结算金额"));
                BigDecimal settleRealAmount = TypeUtils.castToBigDecimal(objectMap.get("累计已付结算金额"));
                BigDecimal noSettleAmount = TypeUtils.castToBigDecimal(objectMap.get("累计应付结算总金额"));
                String remark = (String) objectMap.get("备注");
                BusFinance busFinance = new BusFinance();
                busFinance.setUserId(userId);
                busFinance.setFinanceMonth(financeMonth);
                busFinance.setSaleManId(saleManId);
                busFinance.setDeptId(deptId);
                busFinance.setCompanyId(OpenHelper.getCompanyId());
                busFinance.setSaleAmount(saleAmount);
                busFinance.setReturnAmount(returnAmount);
                busFinance.setDebtAmount(debtAmount);
                busFinance.setImportData(CommonConstants.ENABLED);
                busFinance.setCustomBondAmount(cBondAmount);
                busFinance.setCustomBondReturnAmount(cBondReturnAmount);
                busFinance.setSettleAbleAmount(settleAbleAmount);
                busFinance.setSettleRealAmount(settleRealAmount);
                busFinance.setNoSettleAmount(noSettleAmount);
                busFinance.setRemark(remark);
                busFinance.setFinanceType(1);
                busFinanceList.add(busFinance);
            }
            if (busFinanceList.size() > 0) {
                boolean b = saveBatch(busFinanceList);
                if (b) {
                    return ResultBody.ok();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResultBody.failed("导入失败");
    }


    @Override
    public BusFinance getDateByMonth(BusFinance finance, String financeMonth, Integer financeType) {
        CriteriaQuery<BusFinance> cq = new CriteriaQuery(BusFinance.class);
        cq.eq("deptId", finance.getDeptId());
        cq.eq("saleManId", finance.getSaleManId());
        cq.eq("financeType", financeType);
        cq.eq("financeMonth", financeMonth);
        return getOne(cq, false);
    }


    @Override
    public void exportData(HttpServletResponse response, Long financeId) {
        Map map = (Map) redisUtils.get("DZ:" + financeId);
        if (FlymeUtils.isNotEmpty(map)) {
            Object financeMonth = map.get("financeMonth");
            Object deptName = map.get("deptName");
            Object saleManName = map.get("saleManName");
            TemplateExportParams templateExportParams = new TemplateExportParams("excel/模板对账表.xlsx", true);
            templateExportParams.setStyle(ExcelExportStylerDefaultImpl.class);
            String[] sheetNames = {"对账表" + financeMonth, financeMonth + "明细表", "本期回上期"};
            templateExportParams.setSheetName(sheetNames);
            Workbook workbook = ExcelExportUtil.exportExcel(templateExportParams, map);
            String fileName = "截止" + financeMonth + deptName + saleManName + "对帐表.xlsx";
            try {
                response.reset();
                response.setContentType("application/octet-stream;charset=UTF-8");
                fileName = URLEncoder.encode(fileName, "UTF-8");
                response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
                OutputStream fos = response.getOutputStream();
                workbook.write(fos);
                fos.flush();
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    @Override
    public Map<String, Object> initData(Long financeId) {
        Map<String, Object> exportMap = new HashMap<>();
        //本期合计对象
        BusFinance benQiHjFinance = getById(financeId);
        Long saleManId = benQiHjFinance.getSaleManId();
        BusSaleman saleMan = salemanService.getById(saleManId);
        Long deptId = benQiHjFinance.getDeptId();
        BusDept dept = deptService.getById(deptId);
        //本期月份
        String financeMonth = benQiHjFinance.getFinanceMonth();
        //上期日期
        LocalDate lastMonthDate = LocalDate.parse(financeMonth + "-01");
        //上期月份
        String lastMonth = DateUtils.format(lastMonthDate.minusMonths(1), DateUtils.yyyyMM);


        //对账表月份第一天
        String firstDay = financeMonth + "-01";

        //统计本期合计数据
        List<BusFinanceDetails> orderDetailList = detailsService.initThisBusFinanceDetails(benQiHjFinance);


        //上期累计对象
        BusFinance lastBusFinance = getDateByMonth(benQiHjFinance, lastMonth, 1);

        ApiAssert.isNotEmpty("上期对账表不存在,请先创建上期对账表", lastBusFinance);

        //统计上期数据
        List<BusFinanceDetails> lastDetails = detailsService.selectLastByFinanceId(benQiHjFinance);
        BigDecimal lastReturnAmount = new BigDecimal("0");
        BigDecimal lastTbAmount = new BigDecimal("0");
        BigDecimal lastSettleAmount = new BigDecimal("0");
        BigDecimal lastBzjAmount = new BigDecimal("0");


        //本期调整上期保证金（退货订单）
        List<EntityMap> lastBzjList = orderDetailsService.selectBzjBenQi(deptId, financeMonth, firstDay);

        if (FlymeUtils.isNotEmpty(lastBzjList)) {
            for (EntityMap orderDetails : lastBzjList) {
                BigDecimal customBond = FlymeUtils.getBigDecimal(orderDetails.getBigDecimal("customBond"), "0");
                lastBzjAmount = lastBzjAmount.add(customBond);
            }
        }

        //本期回上期回款
        List<EntityMap> lastReturnList = orderDetailsService.selectByReturnDate(deptId, financeMonth, firstDay);
        if (FlymeUtils.isNotEmpty(lastReturnList)) {
            for (EntityMap orderDetails : lastReturnList) {
                BigDecimal returnAmount = FlymeUtils.getBigDecimal(orderDetails.getBigDecimal("returnAmount"), "0");
                lastReturnAmount = lastReturnAmount.add(returnAmount);
            }
        }

        //本期退上期保证金
        List<EntityMap> lastTbList = orderDetailsService.selectTuiBenQi(deptId, financeMonth, firstDay);
        if (FlymeUtils.isNotEmpty(lastTbList)) {
            for (EntityMap orderDetails : lastTbList) {
                BigDecimal returnCustomBond = FlymeUtils.getBigDecimal(orderDetails.getBigDecimal("returnCustomBond"), "0");
                lastTbAmount = lastTbAmount.add(returnCustomBond);
            }
        }

        List<EntityMap> settleList = new ArrayList<>();
        //本期结算上期
        List<EntityMap> lastSettleList = orderDetailsService.selectJiesuanBenQi(deptId, financeMonth, firstDay);
        List<EntityMap> lastSettleList2 = orderDetailsService.selectJiesuanBenQi2(deptId, financeMonth, firstDay);
        //查询本期结算上期
        if (FlymeUtils.isNotEmpty(lastSettleList)) {
            for (EntityMap entityMap : lastSettleList) {
                BigDecimal settleRealAmount = entityMap.getBigDecimal("settleRealAmount");
                lastSettleAmount = lastSettleAmount.add(settleRealAmount);
            }
            settleList.addAll(lastSettleList);
        }
        //查询本期结算上期(按流向)
        if (FlymeUtils.isNotEmpty(lastSettleList2)) {
            for (EntityMap entityMap : lastSettleList2) {
                BigDecimal settleRealAmount2 = entityMap.getBigDecimal("settleRealAmount2");
                lastSettleAmount = lastSettleAmount.add(settleRealAmount2);
            }
            settleList.addAll(lastSettleList2);
        }


        //本期加入本期回上期
        initExportData(exportMap, benQiHjFinance, lastBusFinance, lastSettleAmount, lastTbAmount, lastReturnAmount, lastBzjAmount);

        exportMap.put("financeMonth", financeMonth);
        exportMap.put("deptName", dept.getDeptName());
        exportMap.put("saleManName", saleMan.getSaleManName());
        //对账表月份最后一天
        exportMap.put("endDate", DateUtils.format(DateUtils.getLastDayOfMonth(firstDay)));
        exportMap.put("lastReturnList", lastReturnList);
        exportMap.put("lastTbList", lastTbList);
        exportMap.put("lastSettleList", settleList);
        exportMap.put("lastDetails", lastDetails);
        exportMap.put("orderDetailList", orderDetailList);
        redisUtils.set("DZ:" + financeId, exportMap);
        return exportMap;
    }


    private void initExportData(Map<String, Object> result, BusFinance benQiHjFinance, BusFinance shangQiLjFinace, BigDecimal lastSettleAmount, BigDecimal lastTbAmount, BigDecimal lastReturnAmount, BigDecimal lastBzjAmount) {


        /**
         * 本期差异记录
         */
        List<BusFinanceDetails> list = detailsService.listByFinanceId(benQiHjFinance.getFinanceId());
        //本期回款差异
        BigDecimal returnAmount1 = new BigDecimal("0");
        //本期应结算差异
        BigDecimal settleAbleAmount1 = new BigDecimal("0");
        //本期已结算差异
        BigDecimal settleRealAmount1 = new BigDecimal("0");
        //本期发货差异
        BigDecimal saleAmount1 = new BigDecimal("0");
        //退资保金
        BigDecimal returnCustomBond1 = new BigDecimal("0");

        if (FlymeUtils.isNotEmpty(list)) {
            for (BusFinanceDetails busFinanceDetails : list) {
                BigDecimal returnAmount = FlymeUtils.getBigDecimal(busFinanceDetails.getReturnAmount(), "0");
                BigDecimal settleAmount = FlymeUtils.getBigDecimal(busFinanceDetails.getSettleAmount(), "0");
                BigDecimal yesSettleAmount = FlymeUtils.getBigDecimal(busFinanceDetails.getYesSettleAmount(), "0");
                BigDecimal saleAmount = FlymeUtils.getBigDecimal(busFinanceDetails.getSaleAmount(), "0");
                BigDecimal returnCustomBond = FlymeUtils.getBigDecimal(busFinanceDetails.getReturnCustomBond(), "0");
                returnAmount1 = returnAmount1.add(returnAmount);
                returnCustomBond1 = returnCustomBond1.add(returnCustomBond);
                settleAbleAmount1 = settleAbleAmount1.add(settleAmount);
                settleRealAmount1 = settleRealAmount1.add(yesSettleAmount);
                saleAmount1 = saleAmount1.add(saleAmount);
            }
        }

        //本期月份
        String financeMonth = benQiHjFinance.getFinanceMonth();


        //上期第一天
        String lastFirstDay = shangQiLjFinace.getFinanceMonth() + "-01";

        //上期最后一天
        String lastEndDay = DateUtils.format(DateUtils.getLastDayOfMonth(lastFirstDay));


        //本期结算金额+本期差异
        BigDecimal settleRealAmount = FlymeUtils.getBigDecimal(benQiHjFinance.getSettleRealAmount(), "0").add(settleRealAmount1);

        //本期已结算=本期回上期+本期已结算
        BigDecimal thisSettleAmount = settleRealAmount.add(lastSettleAmount);

        benQiHjFinance.setSettleRealAmount(thisSettleAmount);

        //本期应结算金额
        BigDecimal thisSettleAbleAmount = FlymeUtils.getBigDecimal(benQiHjFinance.getSettleAbleAmount(), "0").add(settleAbleAmount1);


        benQiHjFinance.setSettleAbleAmount(thisSettleAbleAmount);


        //本期未结算=本期应结算-本期已结算
        benQiHjFinance.setNoSettleAmount(thisSettleAbleAmount.subtract(thisSettleAmount));

        //本期退保证金金额
        BigDecimal thisCustomBondReturnAmount = FlymeUtils.getBigDecimal(benQiHjFinance.getCustomBondReturnAmount(), "0").add(returnCustomBond1);
        //本期退保证金金额
        benQiHjFinance.setCustomBondReturnAmount(thisCustomBondReturnAmount.add(lastTbAmount));
        //本期发货金额+本期发货差异
        BigDecimal thisSaleAmount = FlymeUtils.getBigDecimal(benQiHjFinance.getSaleAmount(), "0").add(saleAmount1);

        //本期回款金额=本期回款+本期回上期+本期差异值
        BigDecimal thisReturnAmount = FlymeUtils.getBigDecimal(benQiHjFinance.getReturnAmount(), "0").add(lastReturnAmount).add(returnAmount1);

        benQiHjFinance.setReturnAmount(thisReturnAmount);

        //本期欠款金额
        BigDecimal thisDebtAmount = thisSaleAmount.subtract(thisReturnAmount);

        benQiHjFinance.setDebtAmount(thisDebtAmount);

        benQiHjFinance.setSaleAmount(thisSaleAmount);


        //本期累计
        BusFinance totalFinance = getDateByMonth(benQiHjFinance, benQiHjFinance.getFinanceMonth(), 1);
        if (FlymeUtils.isEmpty(totalFinance)) {
            totalFinance = new BusFinance();
            totalFinance.setDeptId(benQiHjFinance.getDeptId());
            totalFinance.setFinanceMonth(benQiHjFinance.getFinanceMonth());
            totalFinance.setSaleManId(benQiHjFinance.getSaleManId());
            //更新本期累计
            totalFinance.setFinanceType(1);
            totalFinance.setImportData(0);
            totalFinance.setFinanceState(0);
        }
        BigDecimal saleAmount = FlymeUtils.getBigDecimal(benQiHjFinance.getSaleAmount(), "0");
        BigDecimal debtAmount = FlymeUtils.getBigDecimal(benQiHjFinance.getDebtAmount(), "0");
        BigDecimal cBondAmount = FlymeUtils.getBigDecimal(benQiHjFinance.getCustomBondAmount(), "0").add(lastBzjAmount);
        BigDecimal cBondReturnAmount = FlymeUtils.getBigDecimal(benQiHjFinance.getCustomBondReturnAmount(), "0");
        BigDecimal settleAbleAmount = FlymeUtils.getBigDecimal(benQiHjFinance.getSettleAbleAmount(), "0");

        //本期累计未结算
        BigDecimal settleTotalamount = new BigDecimal("0");

        //本期回款金额
        BigDecimal returnAmount = FlymeUtils.getBigDecimal(benQiHjFinance.getReturnAmount(), "0");

        if (FlymeUtils.isNotEmpty(shangQiLjFinace)) {
            //上期累计不为空
            saleAmount = saleAmount.add(FlymeUtils.getBigDecimal(shangQiLjFinace.getSaleAmount(), "0"));
            returnAmount = returnAmount.add(FlymeUtils.getBigDecimal(shangQiLjFinace.getReturnAmount(), "0"));
            debtAmount = debtAmount.add(FlymeUtils.getBigDecimal(shangQiLjFinace.getDebtAmount(), "0"));
            cBondAmount = cBondAmount.add(FlymeUtils.getBigDecimal(shangQiLjFinace.getCustomBondAmount(), "0"));
            cBondReturnAmount = cBondReturnAmount.add(FlymeUtils.getBigDecimal(shangQiLjFinace.getCustomBondReturnAmount(), "0"));
            settleAbleAmount = settleAbleAmount.add(FlymeUtils.getBigDecimal(shangQiLjFinace.getSettleAbleAmount(), "0"));
            settleRealAmount = settleRealAmount.add(FlymeUtils.getBigDecimal(shangQiLjFinace.getSettleRealAmount(), "0"));
            settleTotalamount = settleAbleAmount.subtract(settleRealAmount.add(lastSettleAmount));
        }
        totalFinance.setSaleAmount(saleAmount);
        totalFinance.setReturnAmount(returnAmount);
        totalFinance.setDebtAmount(debtAmount);
        totalFinance.setCompanyId(shangQiLjFinace.getCompanyId());
        totalFinance.setCustomBondAmount(cBondAmount);
        totalFinance.setCustomBondReturnAmount(cBondReturnAmount);
        totalFinance.setSettleAbleAmount(settleAbleAmount);
        //加上本期结算上期
        totalFinance.setSettleRealAmount(settleRealAmount.add(lastSettleAmount));
        totalFinance.setNoSettleAmount(settleTotalamount);

        //本期未结算
        BigDecimal thisNoSettleAmount = thisSettleAbleAmount.subtract(thisSettleAmount);

        if (FlymeUtils.ltzero(thisNoSettleAmount)) {
            //未结算金额小于0是取本期累计数
            benQiHjFinance.setNoSettleAmount(totalFinance.getNoSettleAmount());
        }
        if (FlymeUtils.ltzero(thisDebtAmount)) {
            //欠款金额小于0是取本期累计数
            benQiHjFinance.setDebtAmount(totalFinance.getDebtAmount());
        }
        Boolean update = checkUpdate(financeMonth);
        Integer state = FlymeUtils.getInteger(benQiHjFinance.getFinanceState(), 0);
        //只更新最近一期对账表
        if (state.equals(0)) {
            //添加本期累计
            saveOrUpdate(totalFinance);
            //更新本期合计
            saveOrUpdate(benQiHjFinance);
        }
        result.put("map1", shangQiLjFinace);
        result.put("map2", benQiHjFinance);
        result.put("map3", totalFinance);
    }

    /**
     * 是否更新合计数据
     *
     * @return
     */
    private Boolean checkUpdate(String financeMonth) {
        Boolean update = false;
        financeMonth = financeMonth + "-01";
        Date firstDay = DateUtils.parseDate(financeMonth);
        Integer lastMonth = firstDay.getMonth();
        String nowMonth = DateUtils.getMonth();
        Integer diffMonth = Integer.parseInt(nowMonth) - lastMonth;
        Date date0 = DateUtils.addMonths(firstDay, diffMonth);
        String data1 = DateUtils.getYear() + "-" + nowMonth + "-01";
        if (DateUtils.formatDate(date0).equals(data1)) {
            update = true;
        }
        return update;
    }
}
